/******************************************************************************
 * $Id: utils_inline.h,v 1.11 2004/09/22 01:14:28 jimb Exp $
 * @file
 * @author  Jim Brooks http://www.jimbrooks.org
 * @brief   Utility functions.
 ******************************************************************************/

#ifndef UTILS_INLINE_H
#define UTILS_INLINE_H

/******************************************************************************
 * Clear a memory segment.
 ******************************************************************************/
extern inline void
CLEAR( void* p, int n )
{
   memset( p, 0, n );
}

/******************************************************************************
 * @return True if a char is whitespace.
 ******************************************************************************/
extern inline int
IsWhitespace( gunichar c )
{
//   return tableWhitespace[ (int)c ];
	 return g_unichar_isspace(c);
}

/******************************************************************************
 * (pure C) @return True if a char can be of a C identifier.
 ******************************************************************************/
extern inline int
IsCIdChar( gunichar c )
{
//   return tableCIdentifier[ (int)c ];
	return g_unichar_isalnum(c) || c == '_';
}

/******************************************************************************
 * (C/C++/Java) @return True if a char can be of a C-ish identifier.
 ******************************************************************************/
extern inline int
IsCishIdChar( gunichar c )
{
//   return tableCishIdentifier[ (int)c ];
   return g_unichar_isalnum(c) ||
		  c == '_' ||
		  c == '~' ;
}

/******************************************************************************
 * @return True if a char is a symbol char.
 * @remarks '_' (underscore) is NOT considered a symbol.
 ******************************************************************************/
extern inline int
IsSymbolChar( gunichar c )
{
//   return tableSymbol[ (int)c ];
   return ( (c >= '!' && c <='/' ) ||
	        (c >= ':' && c <='@' ) ||
			(c >= '[' && c <=0x60) ||
			(c >= '{' && c <='~' )
		  )
	    && c !='_';
}

/******************************************************************************
 * @return True if a char is a C symbol char.
 ******************************************************************************/
extern inline int
IsCSymbolChar( gunichar c )
{
  /*
   * Exclude '#' so that #define will be parsed singularly.
   */
   return c != '#'  &&  IsSymbolChar(c);
}

/******************************************************************************
 * Find a C symbol char in a string.
 ******************************************************************************/
extern inline const char*
FindCSymbolChar( const char* pStr,
                 int         len )
{
   const char*	pc;

#ifndef HYPERSRC_SPEED
g_return_val_if_fail( pStr  &&  len > 0  &&  len < MAX_TEXT_BUFFER_LEN, NULL );
#endif

  /*
   * Stop when symbol char, or past string, or null char.
   */
   for ( pc = pStr;
         pc < &pStr[len]  &&  *pc;
         ++pc )
   {
      if ( IsCSymbolChar( *pc ) ) return pc;
   }

   return NULL;
}

/******************************************************************************
 * @return True if a UNIX end-of-line (LF) is pointed to.
 ******************************************************************************/
extern inline int
IsEolUnix( const char* pc )
{
#ifndef HYPERSRC_SPEED
g_assert( pc );
#endif

   return *pc == CHAR_LF;
}

/******************************************************************************
 * @return True if a MSDOS end-of-line (LF/CR) is pointed to.
 ******************************************************************************/
extern inline int
IsEolMsdos( const char* pc )
{
#ifndef HYPERSRC_SPEED
g_assert( pc );
#endif

   return pc[0] == CHAR_LF  &&  pc[1] == CHAR_CR;
}

/******************************************************************************
 * @return True if EOL is pointed to (either MSDOS or UNIX).
 ******************************************************************************/
extern inline int
IsEol( const char* pc )
{
#ifndef HYPERSRC_SPEED
g_assert( pc );
#endif

  /*
   * Actually IsEolUnix() will short-circuit MSDOS EOLs.
   */
   return IsEolUnix( pc ) || IsEolMsdos( pc );
}

/******************************************************************************
 * @return True if a pointer points to an empty line.
 ******************************************************************************/
extern inline int
IsLineEmpty( const char* pLine )
{
#ifndef HYPERSRC_SPEED
g_assert( pLine );
#endif

   return IsEol( pLine )  ||  *pLine == '\0';
}

/******************************************************************************
 * Copy a set of chars (not necessarily a string) into a destination string.
 * The destination string will be terminated by a null byte.
 ******************************************************************************/
extern inline void
CopyChars( char*       pDest,
           const char* pSrc,
           int         amount )
{
#ifndef HYPERSRC_SPEED
//g_assert( pDest && pSrc && (amount <= MAX_STRING_LEN) );
g_assert( pDest );
g_assert( pSrc);
g_assert( amount <= MAX_STRING_LEN);
#endif

  /*
   * memcpy() is used because a set of chars is being copied,
   * not necessarily a null-terminated string.
   * After the copy, append a null byte to the destination string.
   */
   memcpy( pDest, pSrc, amount );
   pDest[amount] = '\0';
}

/******************************************************************************
 * Move a pointer past a word.
 * @param   pWord
 *          Pointer to the first char of the word.
 * @param   size
 *          The amount of chars in the word.
 * @return  pointer to next char after the last char of a word
 ******************************************************************************/
extern inline const char*
PastWord( const char* pWord,
          int         size )
{
#ifndef HYPERSRC_SPEED
g_assert( pWord );
#endif

   return pWord + size;
}

/******************************************************************************
 * Move past whitespace.
 * @param   max
 *          Aborts if this amount of chars has been scanned.
 * @return  Pointer to the first non-whitespace char
 *          -or- NULL upon failure.
 ******************************************************************************/
extern inline const char*
PastWhitespace( const char* pc,
                int         max )
{
   int i;

#ifndef HYPERSRC_SPEED
g_assert( pc );
#endif

   for ( i = 0; i < max; ++i )
   {
      if ( ! IsWhitespace( pc[i] ) ) return &pc[i];
   }

   return NULL;
}

/******************************************************************************
 * Allocate memory for a string.
 * DeleteString() should be called to delete the string.
 * @param   size
 *          Size of the string (excluding the trailing null byte).
 * @return  Pointer to the first char of the allocated string
 *          -or- NULL upon failure.
 ******************************************************************************/
extern inline char*
CreateString( int size )
{
#ifndef HYPERSRC_SPEED
g_return_val_if_fail( size > 0, NULL );
#endif

  /*
   * Allocate one extra byte for the trailing null byte.
   */
   return g_malloc0( size+1 );
}

/******************************************************************************
 * Clone a string.
 * To delete the string, only DeleteString() should be called.
 * @param   src
 *          String to be cloned.
 * @return  Pointer to the first char of the allocated string
 *          -or- NULL upon failure.
 ******************************************************************************/
extern inline char*
CloneString( const char* src )
{
   int		len;
   char*	dest;

#ifndef HYPERSRC_SPEED
g_assert( src );
#endif

   len = StrLen( src );							/* len doesn't count null byte */
   dest = CreateString( StrLen(src) + 1 );		/* + 1 for null byte */
   CopyChars( dest, src, len );					/* does write a null byte */
   return dest;
}

/******************************************************************************
 * Fast version of CloneString() (ideal when length of string is known).
 ******************************************************************************/
extern inline char*
FastCloneString( const char* src,
                 int         len )
{
   char*	dest;

   dest = g_malloc( len + 1 );		/* +1 for null byte */
   memcpy( dest, src, len );
   dest[len] = '\0';				/* write null byte */
   return dest;
}

/******************************************************************************
 * Delete a string that was allocated by CreateString().
 ******************************************************************************/
extern inline void
DeleteString( char* p )
{
#if 0
/* passing NULL is OK */
#ifdef HYPERSRC_PEDANTIC
g_assert( p );
#endif
#endif

   g_free( p );
}

/*****************************************************************************
 * @return TRUE if string is empty.
 *****************************************************************************/
extern inline int
IsStringEmpty( const char* str )
{
   if ( str  &&  str[0] )
      return FALSE;
   else
      return TRUE;
}

/*****************************************************************************
 * Similar to strcmp(), but returns non-zero if either string is NULL.
 * (Note that strcmp() would segfault in this case.)
 *****************************************************************************/
extern inline int
CompareStrings( const char* s1,
                const char* s2 )
{
  /*
   * -- Other code depends on these NULL checks, don't optimize them away --
   */
   if ( s1  &&  s2 )
      return strcmp( s1, s2 );
   else
      return -1;
}

/*****************************************************************************
 * Compare two strings, ignoring case.
 * @return Non-zero if either string is NULL or aren't equivalent.
 *****************************************************************************/
extern inline int
CompareStringsNonCase( const char* s1,
                       const char* s2 )
{
  /*
   * -- Other code depends on these NULL checks, don't optimize them away --
   */
   if ( s1  &&  s2 )
      return strcasecmp( s1, s2 );
   else
      return -1;
}

/*****************************************************************************
 * Wrapper to select strncmp() or strncasecmp().
 *****************************************************************************/
extern inline int
Strncmpx( const char* s1,
          const char* s2,
          size_t      n,
          gboolean    caseSens )
{
   if ( caseSens )
      return strncmp( s1, s2, n );
   else
      return strncasecmp( s1, s2, n );
}

#endif /* UTILS_INLINE_H */
